using System.Collections.Generic;
using UnityEngine;

public class TableIntersectionSearch : Singleton<TableIntersectionSearch>
{
	public class Intersection
	{
		public bool isSet;

		public Vector3 position;

		public float dz;
	}

	private struct DirectionRangeIntersection
	{
		public Vector3 direction;

		public float distance;
	}

	private class DirectionRangeIntersectionComparer : Singleton<DirectionRangeIntersectionComparer>, IComparer<DirectionRangeIntersection>
	{
		public int Compare(DirectionRangeIntersection a, DirectionRangeIntersection b)
		{
			return a.direction.x.CompareTo(b.direction.x);
		}
	}

	public Intersection enter = new Intersection();

	public Intersection exit = new Intersection();

	private float minZ;

	private float opponentTableSide;

	private ZeroMemoryReleaseList<DirectionRangeIntersection> rangeIntersections = new ZeroMemoryReleaseList<DirectionRangeIntersection>();

	public bool isIntersectionFound
	{
		get
		{
			return enter.isSet && exit.isSet;
		}
	}

	public float onTableLength
	{
		get
		{
			return Vector3Ex.HorizontalDistance(enter.position, exit.position);
		}
	}

	public void Clear()
	{
		enter.isSet = (exit.isSet = false);
	}

	public void FindIntersectionsWithTable(Vector3 initialPosition, Vector3 direction, float opponentTableSide, float minZ = 0f)
	{
		Clear();
		this.opponentTableSide = opponentTableSide;
		this.minZ = minZ;
		direction.Normalize();
		TryAddIntersectionWithZ(initialPosition, direction, Mathf.Sign(opponentTableSide) * minZ);
		TryAddIntersectionWithZ(initialPosition, direction, Mathf.Sign(opponentTableSide) * Table.halfLength);
		TryAddIntersectionWithX(initialPosition, direction, 0f - Table.halfwidth);
		TryAddIntersectionWithX(initialPosition, direction, Table.halfwidth);
	}

	private bool TryAddIntersectionWithZ(Vector3 initialPosition, Vector3 direction, float z)
	{
		if (direction.z != 0f)
		{
			float num = direction.x / direction.z;
			float num2 = z - initialPosition.z;
			if (num2 == 0f || Mathf.Sign(num2) == Mathf.Sign(direction.z))
			{
				Vector3 intersection = new Vector3(initialPosition.x + num2 * num, 0f, z);
				if (isIntersectionOnTable(intersection))
				{
					Add(intersection, num2);
					return true;
				}
			}
		}
		return false;
	}

	private bool TryAddIntersectionWithX(Vector3 initialPosition, Vector3 direction, float x)
	{
		if (direction.x != 0f)
		{
			float num = direction.z / direction.x;
			float num2 = x - initialPosition.x;
			if (num2 == 0f || Mathf.Sign(num2) == Mathf.Sign(direction.x))
			{
				Vector3 intersection = new Vector3(x, 0f, initialPosition.z + num2 * num);
				if (isIntersectionOnTable(intersection))
				{
					Add(intersection, num2 * num);
					return true;
				}
			}
		}
		return false;
	}

	private bool isIntersectionOnTable(Vector3 intersection)
	{
		return (Mathf.Sign(intersection.z) == Mathf.Sign(opponentTableSide) || intersection.z == 0f) && Table.IsPosOnTable(intersection) && Mathf.Abs(intersection.z) >= Mathf.Abs(minZ);
	}

	private void Add(Vector3 intersection, float dz)
	{
		dz = Mathf.Abs(dz);
		if (!enter.isSet || enter.dz >= dz)
		{
			enter.isSet = true;
			enter.position = intersection;
			enter.dz = dz;
		}
		if (!exit.isSet || exit.dz <= dz)
		{
			exit.isSet = true;
			exit.position = intersection;
			exit.dz = dz;
		}
	}

	public Vector3Range GetHorizontalDirectionRange(Vector3 position, float opponentTableSide, float minZ)
	{
		rangeIntersections.Clear();
		opponentTableSide = Mathf.Sign(opponentTableSide);
		Vector3 normalized = (new Vector3(0f - Table.halfwidth, 0f, opponentTableSide * Mathf.Abs(minZ)) - position).normalized;
		FindIntersectionsWithTable(position, normalized, opponentTableSide, minZ);
		rangeIntersections.Add(new DirectionRangeIntersection
		{
			direction = normalized,
			distance = onTableLength
		});
		Vector3 normalized2 = (new Vector3(0f - Table.halfwidth, 0f, opponentTableSide * Table.halfLength) - position).normalized;
		FindIntersectionsWithTable(position, normalized2, opponentTableSide, minZ);
		rangeIntersections.Add(new DirectionRangeIntersection
		{
			direction = normalized2,
			distance = onTableLength
		});
		Vector3 normalized3 = (new Vector3(Table.halfwidth, 0f, opponentTableSide * Mathf.Abs(minZ)) - position).normalized;
		FindIntersectionsWithTable(position, normalized3, opponentTableSide, minZ);
		rangeIntersections.Add(new DirectionRangeIntersection
		{
			direction = normalized3,
			distance = onTableLength
		});
		Vector3 normalized4 = (new Vector3(Table.halfwidth, 0f, opponentTableSide * Table.halfLength) - position).normalized;
		FindIntersectionsWithTable(position, normalized4, opponentTableSide, minZ);
		rangeIntersections.Add(new DirectionRangeIntersection
		{
			direction = normalized4,
			distance = onTableLength
		});
		rangeIntersections.Sort(Singleton<DirectionRangeIntersectionComparer>.instance);
		Vector3Range vector3Range = new Vector3Range();
		vector3Range.min = Vector3.Lerp(rangeIntersections[0].direction, rangeIntersections[1].direction, 0.5f);
		vector3Range.max = Vector3.Lerp(rangeIntersections[2].direction, rangeIntersections[3].direction, 0.5f);
		return vector3Range;
	}
}
